package cn.tedu.springbootdemo.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * AOP主要的使用场景：
 * 1.日志与跟踪
 * 2.事务管理 @Transactional的底层就是AOP
 * 3.安全
 * 4.缓存
 * 5.错误处理
 * 6.性能监测
 * 7.自定义业务规则
 *
 * 1.导入Spring AOP依赖时，便会导入了AspectJ
 * AspectJ:最早的AOP技术（1995年推出第一个版本），一个完整的面向切面编程语言
 * Spring AOP：基于Java的AOP框架，集成了AspectJ
 * 2.切面组件，封装了横切关注点代码
 * 3.标注通知：@Before
 * 4.标注切入点
 * 5.在切面中获取用户调用的方法：连接点
 */
//@Aspect  //@Aspect 注解标记的类 称为切面类
//@Component
public class AspectDemo {
    /**
     * @Ponitcut统一管理切入点
     * -定义一个切入点表达式
     * -将切入点表达式绑定到一个方法
     * -其他通知，只需要绑定方法名即可
     */
    /**
     * 切入点表达式
     * Execution:执行
     * execution(<方法模式>) 该方法必须匹配模式规则
     * 可以串联起来创建复合切入点
     *  --&&(与)， ||(或)，！(非)
     *  --execution(<方法模式1>) || execution(<方法模式2>)
     *
     *  方法模式:
     *      [修饰符] 返回值类型 [类的类型] 方法名称（参数列表） [throws异常类型]
     */
//    @Pointcut("bean(userServiceImpl)")
    //需求：类名以Service结尾，方法名以Username结尾的任意方法 @Pointcut("execution(* *Service.*Usernaem(..))")
    //需求：包名以cn开头，子包为service的任意方法  @Pointcut("execution(* cn..service.*.*(..))")
    //需求：匹配类名是以Service结尾  @Pointcut("execution(* *Service.*(..))")
    //需求：
    @Pointcut("execution(* cn.tedu.springbootdemo.service.UserService.login(String,String)) ||" +
        "execution(* cn.tedu.springbootdemo.service.AwardService.getAward(..))")
    public void userService(){}

    //@Before:前置通知 ，在目标方法执行之前执行
    @Before("userService()")
    public void test(JoinPoint point){
        //JoinPoint:连接点，就是AOP方法的插入位置

        Signature signature = point.getSignature();
        //toLongString 可以获取目标方法的修饰符、返回值类型、名称和参数类型等信息
        System.out.println("signature.toLongString() = " + signature.toLongString());
        //toShortString 返回目标方法的类型和方法名以及参数信息
        System.out.println("signature.toShortString() = " + signature.toShortString());
        //getDeclaringType ：返回声明目标方法的类的Class对象
        System.out.println("signature.getDeclaringType() = " + signature.getDeclaringType());
        System.out.println(signature.getName()+"方法执行之前执行");
    }

    //@After：后置通知，在目标方法执行之后去执行的通知，不论目标方法是否正常执行都会执行的通知
    @After("userService()")
    public void testAfter(JoinPoint point){
        System.out.println(point.getSignature().getName()+"方法执行之后执行");
    }

    //@AfterReturning：后置通知,在目标方法正常执行之后才会执行的通知，如果有异常，将不会执行通知
    @AfterReturning("userService()")
    public void testAfterReturning(JoinPoint point){
        System.out.println(point.getSignature().getName()+"方法正常执行之后执行");
    }

    //@AfterThrowing： 后置通知，当目标方法出现异常时才会执行
    @AfterThrowing("userService()")
    public void testAfterThrowing(JoinPoint point){
        System.out.println(point.getSignature().getName()+"方法出现异常执行之后执行");
    }




}
